package imp

import (
	sqlc "bgs/db/sqlc"
	productGrpc "bgs/grpc/gen/service/product"
	"bgs/grpc/gen/shared/message"
	"bgs/grpc/imp/constants"
	"bgs/grpc/imp/enums"
	"bgs/util"
	"strconv"
	"time"

	// "bytes"
	"context"
	"database/sql"
	"encoding/json"

	// "fmt"
	pg "github.com/lib/pq"
	// "strings"
)

/****************************************************************************************/
/*                               product entity of helper                               */
/****************************************************************************************/
// func mapProductEntityFilteredToPb(list []sqlc.Product, f func(sqlc.Product) *productGrpc.ProductEntity) []*productGrpc.ProductEntity {
// 	r := make([]*productGrpc.ProductEntity, len(list))
// 	for i, item := range list {
// 		r[i] = f(item)
// 	}
// 	return r
// }
/****************************************************************************************/
/*                               product entity of cmd                                  */
/****************************************************************************************/

// CreateProductOld 新增商品
func (s *ProductAPIService) CreateProductOld(ctx context.Context, req *productGrpc.CreateProductRequest) (res *productGrpc.CreateProductResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("productImp->CreateProductOld:%v", req)
	res = &productGrpc.CreateProductResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	var product sqlc.Product
	var productAttributeKeys []sqlc.ProductAttributeKey
	var productAttributeValues []sqlc.ProductAttributeValue
	var productSpecs []sqlc.ProductSpec
	var priceMin int32
	var priceMax int32
	hasSpecs := len(req.ProductSpecs) > 0

	if hasSpecs {
		maxProductSpec, minProductSpec := util.MaxWithMin(util.ToGenericSlice(req.ProductSpecs), func(i1, i2 interface{}) util.Ord {
			ps1, ps2 := i1.(*productGrpc.ProductSpecEntity), i2.(*productGrpc.ProductSpecEntity)
			return (util.IfThenElse(ps1.Price-ps2.Price < 0, util.Lt, util.Gt)).(util.Ord)
		})
		priceMax, priceMin = maxProductSpec.(*productGrpc.ProductSpecEntity).Price, minProductSpec.(*productGrpc.ProductSpecEntity).Price
	} else {
		priceMax = req.Price
		priceMin = req.Price
	}
	slog.Infof("max,min %v, %v", priceMax, priceMin)

	err = s.dao.NewTxRunner().ExecTx(ctx, func(tx *sql.Tx) (err error) {

		q := sqlc.New(tx)

		txTime := time.Now()
		syncAction := string(sqlc.EmSyncActionLCR)

		product, err = q.CreateProduct(ctx, sqlc.CreateProductParams{
			// Origin:          req.Origin,
			BrandID:         req.BrandId,
			Name:            req.Name,
			Pics:            req.Pics,
			Intro:           sqlc.NSFromString(req.Intro),
			IntroPics:       req.IntroPics,
			HasSpecs:        hasSpecs,
			PriceMin:        priceMin,
			PriceMax:        priceMax,
			ProductGroupID:  sqlc.NInt64FromInt64(req.ProductGroupId),
			// RemotePrdTypeID: req.RemotePrdTypeId,
			// RemotePk:        req.RemotePk,
		})
		if err != nil {
			return err
		}
		slog.Infof("1 创建产品 ok")
		localPKOfProduct := strconv.FormatInt(product.ID, 10)
		remotePkOfProduct := strconv.FormatInt(product.RemotePk, 10)

		//2 商品设置同步
		localObjOfProduct, localPkNameOfProduct, localFieldsOfProduct := constants.SyncLocalObjProduct, constants.SyncLocalPkNameProduct, constants.SyncLocalFieldsProduct
		remoteObjOfProduct, remotePkNameOfProduct, remoteFieldsOfProduct := constants.SyncRemoteObjProduct, constants.SyncRemotePkNameProduct, constants.SyncRemoteFieldsProduct

		syncOfProduct, err := q.UpsertSync(ctx, sqlc.UpsertSyncParams{
			LocalObj:         localObjOfProduct,
			LocalPkName:      localPkNameOfProduct,
			LocalFields:      localFieldsOfProduct,
			RemoteObj:        remoteObjOfProduct,
			RemotePkName:     remotePkNameOfProduct,
			RemoteFields:     remoteFieldsOfProduct,
			LatestSynced:     txTime,
			LatestSyncAction: syncAction,
		})
		if err != nil {
			return err
		}
		slog.Info("2 grpc商品同步 ok")

		// 3 设置同步映射
		syncMappingOfProduct, err := q.UpsertSyncMapping(ctx, sqlc.UpsertSyncMappingParams{
			SyncID:    syncOfProduct.ID,
			LocalObj:  localObjOfProduct,
			LocalPk:   localPKOfProduct,
			RemoteObj: remoteObjOfProduct,
			RemotePk:  remotePkOfProduct,
		})
		if err != nil {
			return err
		}
		slog.Info("3 grpc商品同步映射 ok")

		// 4 设置同步日志
		syncDataOfProduct, err := json.Marshal(product)
		if err != nil {
			return err
		}

		maxVer, err := q.GetSyncLogMaxVer(ctx, sqlc.NInt64FromInt64(syncMappingOfProduct.ID))
		if err != nil {
			return err
		}
		_, err = q.CreateSyncLog(ctx, sqlc.CreateSyncLogParams{
			SyncID:        syncOfProduct.ID,
			SyncMappingID: sqlc.NInt64FromInt64(syncMappingOfProduct.ID),
			LocalObj:      localObjOfProduct,
			LocalPk:       localPKOfProduct,
			RemoteObj:     remoteObjOfProduct,
			RemotePk:      remotePkOfProduct,
			Synced:        txTime,
			Action:        syncAction,
			Data:          syncDataOfProduct,
			SyncStatus:    string(enums.SyncStatusDone),
			Ver:           int64(maxVer + 1),
		})
		if err != nil {
			return err
		}
		slog.Info("4 grpc商品同步日志 ok")

		// 5 设置同步远程对象
		_, err = q.UpsertSyncRemote(ctx, sqlc.UpsertSyncRemoteParams{
			SyncID:    syncOfProduct.ID,
			RemoteObj: remoteObjOfProduct,
			RemotePk:  remotePkOfProduct,
			// Data:      []byte(req.SyncRemoteData),
		})

		if err != nil {
			return err
		}
		slog.Info("5 grpc商品同步远程对象 ok")

		if hasSpecs {
			// 6 批量插入产品属性键
			batchInsertProductAttributeKeySQL := pg.CopyIn("product_attribute_keys", "product_id", "name", "sort_no", "remote_pk")
			stmtOfProductAttributeKey, err := tx.PrepareContext(ctx, batchInsertProductAttributeKeySQL)
			if err != nil {
				return err
			}
			for idx, item := range req.ProductAttributeDefs {
				remotePKOfAttributeKey := 0
				_, err = stmtOfProductAttributeKey.ExecContext(ctx, product.ID, item.Key, idx+1, remotePKOfAttributeKey)
				if err != nil {
					return err
				}
			}
			err = stmtOfProductAttributeKey.Close()
			if err != nil {
				return err
			}
			slog.Infof("6 批量插入产品属性键 ok")

			productAttributeKeys, err = q.ListNormalProductAttributeKeysByProductID(ctx, product.ID)
			if err != nil {
				return err
			}
			slog.Infof("6 读取插入的产品属性键(%d条) ok", len(productAttributeKeys))

			//12 商品设置同步
			localObjOfProductAttributeKey, localPkNameOfProductAttributeKey, localFieldsOfProductAttributeKey := constants.SyncLocalObjProductAttributeKey, constants.SyncLocalPkNameProductAttributeKey, constants.SyncLocalFieldsProductAttributeKey
			remoteObjOfProductAttributeKey, remotePkNameOfProductAttributeKey, remoteFieldsOfProductAttributeKey := constants.SyncRemoteObjProductAttributeKey, constants.SyncRemotePkNameProductAttributeKey, constants.SyncRemoteFieldsProductAttributeKey

			syncOfProductAttributeKey, err := q.UpsertSync(ctx, sqlc.UpsertSyncParams{
				LocalObj:         localObjOfProductAttributeKey,
				LocalPkName:      localPkNameOfProductAttributeKey,
				LocalFields:      localFieldsOfProductAttributeKey,
				RemoteObj:        remoteObjOfProductAttributeKey,
				RemotePkName:     remotePkNameOfProductAttributeKey,
				RemoteFields:     remoteFieldsOfProductAttributeKey,
				LatestSynced:     txTime,
				LatestSyncAction: syncAction,
			})
			if err != nil {
				return err
			}
			slog.Info("7 grpc商品属性键同步 ok")

			productAttributeKeyMap := make(map[string]int64) // key->name, id->value,因为在一个产品下,name唯一
			var syncMappingOfProductAttributeKey sqlc.SyncMapping
			for _, s := range productAttributeKeys {
				productAttributeKeyMap[s.Name] = s.ID

				localPKOfProductAttributeKey := strconv.FormatInt(s.ID, 10)
				remotePkOfProductAttributeKey := "-1" //strconv.FormatInt(s.RemotePk, 10)
				// 设置grpc商品属性键同步映射
				syncMappingOfProductAttributeKey, err = q.UpsertSyncMapping(ctx, sqlc.UpsertSyncMappingParams{
					SyncID:    syncOfProductAttributeKey.ID,
					LocalObj:  localObjOfProductAttributeKey,
					LocalPk:   localPKOfProductAttributeKey,
					RemoteObj: remoteObjOfProductAttributeKey,
					RemotePk:  remotePkOfProductAttributeKey,
				})
				if err != nil {
					return err
				}

				// 设置grpc商品属性键同步日志
				syncDataOfProductAttributekey, err := json.Marshal(s)
				if err != nil {
					return err
				}

				maxVer, err := q.GetSyncLogMaxVer(ctx, sqlc.NInt64FromInt64(syncMappingOfProductAttributeKey.ID))
				if err != nil {
					return err
				}
				_, err = q.CreateSyncLog(ctx, sqlc.CreateSyncLogParams{
					SyncID:        syncOfProductAttributeKey.ID,
					SyncMappingID: sqlc.NInt64FromInt64(syncMappingOfProductAttributeKey.ID),
					LocalObj:      localObjOfProductAttributeKey,
					LocalPk:       localPKOfProductAttributeKey,
					RemoteObj:     remoteObjOfProductAttributeKey,
					RemotePk:      remotePkOfProductAttributeKey,
					Synced:        txTime,
					Action:        syncAction,
					Data:          syncDataOfProductAttributekey,
					SyncStatus:    string(enums.SyncStatusDone),
					Ver:           int64(maxVer + 1),
				})
				if err != nil {
					return err
				}
			}
			slog.Info("8 grpc商品属性键同步映射、grpc商品属性键同步日志")

			// for _, item := range req.ProductAttributeDefs {
			// 	// 设置grpc商品属性键同步远程对象
			// 	_, err = q.UpsertSyncRemote(ctx, sqlc.UpsertSyncRemoteParams{
			// 		SyncID:    syncOfProductAttributeKey.ID,
			// 		RemoteObj: remoteObjOfProductAttributeKey,
			// 		RemotePk:  strconv.FormatInt(item.RemotePk, 10),
			// 		Data:      []byte(item.SyncRemoteData),
			// 	})

			// 	if err != nil {
			// 		return err
			// 	}
			// }
			slog.Info("9 grpc商品属性键同步远程对象 ok")

			batchInsertProductAttributeValueSQL := pg.CopyIn("product_attribute_values", "product_id", "product_attribute_key_id", "value", "sort_no")
			stmtOfProductAttributeValue, err := tx.PrepareContext(ctx, batchInsertProductAttributeValueSQL)
			if err != nil {
				return err
			}
			x := 0
			for _, itemKey := range req.ProductAttributeDefs {
				for idx, itemValue := range itemKey.Values {
					_, err := stmtOfProductAttributeValue.ExecContext(ctx, product.ID, productAttributeKeyMap[itemKey.Key], itemValue, idx+1)
					if err != nil {
						return err
					}
					x++
				}
			}
			err = stmtOfProductAttributeValue.Close()
			if err != nil {
				return err
			}
			slog.Infof("10 批量插入产品属性值(%d条) ok", x)

			productAttributeValues, err = q.ListNormalProductAttributeValuesByProductID(ctx, product.ID)
			if err != nil {
				return err
			}
			slog.Infof("11 读取插入的产品属性值(%d条) ok", len(productAttributeValues))

			/* 方法1 struct->json->raw sql 这里 ProductAttributeEntity是struct
			var buffer bytes.Buffer
			firstItem := req.ProductSpecs[0]
			attributeValuesFirst := util.MapToString(util.ToGenericSlice(firstItem.ProductAttributes), func(v interface{}) string {
				pav := v.(*productGrpc.ProductAttributeEntity)
				return pav.Value
			})
			specNameFirst := strings.Join(attributeValuesFirst, "/")
			productAttributesFirst, err := json.Marshal(firstItem.ProductAttributes)
			if err != nil {
				return err
			}
			buffer.WriteString(fmt.Sprintf("('%s'::em_data_source,%d, %d, '%s'::jsonb, '%s', %d, %d)", product.Origin, product.BrandID, product.ID, productAttributesFirst, specNameFirst, firstItem.Price, firstItem.RemotePk))
			for _, item := range req.ProductSpecs[1:] {
				attributeValues := util.MapToString(util.ToGenericSlice(item.ProductAttributes), func(v interface{}) string {
					pav := v.(*productGrpc.ProductAttributeEntity)
					return pav.Value
				})
				specName := strings.Join(attributeValues, "/")
				productAttributes, err := json.Marshal(item.ProductAttributes)
				if err != nil {
					return err
				}
				buffer.WriteString(fmt.Sprintf(",('%s'::em_data_source,%d, %d, '%s'::jsonb, '%s', %d, %d)", product.Origin, product.BrandID, product.ID, productAttributes, specName, item.Price, item.RemotePk))
			}
			*/

			/* 方法2 json ->raw sql 这里 ProductAttributeEntity是json string
			var buffer bytes.Buffer
			for _, item := range req.ProductSpecs {
				// x, _ := util.SliceFromJSON(item.ProductAttributesStr)
				slog.Infof("x=>%v", x)
				buffer.WriteString(fmt.Sprintf(",('%s'::em_data_source,%d, %d, '%s'::jsonb, '%s', %d, %d)", product.Origin, product.BrandID, product.ID, item.ProductAttributesStr, item.Name, item.Price, item.RemotePk))
			}
			valuesStr := strings.TrimPrefix(buffer.String(), ",")
			batchInsertProductSpecSQL := fmt.Sprintf("INSERT INTO product_specs (origin, brand_id, product_id, product_attributes, name, price, remote_pk) VALUES %s", valuesStr)
			// fmt.Println("batchInsertProductSpecSQL=>", batchInsertProductSpecSQL)
			stmtOfProductSpec, err := tx.PrepareContext(ctx, batchInsertProductSpecSQL)
			if err != nil {
				return err
			}
			slog.Infof("stmtOfProductSpec=>", stmtOfProductSpec)
			_, err = stmtOfProductSpec.ExecContext(ctx)
			if err != nil {
				return err
			}
			slog.Infof("exec success")
			err = stmtOfProductSpec.Close()
			if err != nil {
				return err
			}
			*/

			var produceSpec sqlc.ProductSpec
			var syncMappingOfProductSpec sqlc.SyncMapping
			//12 商品设置同步
			localObjOfProductSpec, localPkNameOfProductSpec, localFieldsOfProductSpec := constants.SyncLocalObjProductSpec, constants.SyncLocalPkNameProductSpec, constants.SyncLocalFieldsProductSpec
			remoteObjOfProductSpec, remotePkNameOfProductSpec, remoteFieldsOfProductSpec := constants.SyncRemoteObjProductSpec, constants.SyncRemotePkNameProductSpec, constants.SyncRemoteFieldsProductSpec
			syncOfProductSpec, err := q.UpsertSync(ctx, sqlc.UpsertSyncParams{
				LocalObj:         localObjOfProductSpec,
				LocalPkName:      localPkNameOfProductSpec,
				LocalFields:      localFieldsOfProductSpec,
				RemoteObj:        remoteObjOfProductSpec,
				RemotePkName:     remotePkNameOfProductSpec,
				RemoteFields:     remoteFieldsOfProductSpec,
				LatestSynced:     txTime,
				LatestSyncAction: syncAction,
			})
			if err != nil {
				return err
			}
			slog.Info("12 grpc商品规格同步 ok")

			for _, item := range req.ProductSpecs {
				// 方法3,因为在一个事务里,数量也不大,可以用sqlc的单个插入
				produceSpec, err = q.UpsertProductSpec(ctx, sqlc.UpsertProductSpecParams{
					Origin:            product.Origin,
					BrandID:           product.BrandID,
					ProductID:         product.ID,
					ProductAttributes: json.RawMessage(item.ProductAttributes),
					Name:              item.Name,
					Price:             item.Price,
					RemotePk:          0,
					// RemotePk:          item.RemotePk,
				})
				if err != nil {
					return err
				}
				productSpecs = append(productSpecs, produceSpec)

				localPKOfProductSpec := strconv.FormatInt(produceSpec.ID, 10)
				remotePkOfProductSpec := strconv.FormatInt(produceSpec.RemotePk, 10)
				// 设置商品规格同步映射
				syncMappingOfProductSpec, err = q.UpsertSyncMapping(ctx, sqlc.UpsertSyncMappingParams{
					SyncID:    syncOfProductSpec.ID,
					LocalObj:  localObjOfProductSpec,
					LocalPk:   localPKOfProductSpec,
					RemoteObj: remoteObjOfProductSpec,
					RemotePk:  remotePkOfProductSpec,
				})
				if err != nil {
					return err
				}

				// 10 设置商品规格同步日志
				syncDataOfProductSpec, err := json.Marshal(produceSpec)
				if err != nil {
					return err
				}
				maxVer, err := q.GetSyncLogMaxVer(ctx, sqlc.NInt64FromInt64(syncMappingOfProductSpec.ID))
				if err != nil {
					return err
				}
				_, err = q.CreateSyncLog(ctx, sqlc.CreateSyncLogParams{
					SyncID:        syncOfProductSpec.ID,
					SyncMappingID: sqlc.NInt64FromInt64(syncMappingOfProductSpec.ID),
					LocalObj:      localObjOfProductSpec,
					LocalPk:       localPKOfProductSpec,
					RemoteObj:     remoteObjOfProductSpec,
					RemotePk:      remotePkOfProductSpec,
					Synced:        txTime,
					Action:        syncAction,
					Data:          syncDataOfProductSpec,
					SyncStatus:    string(enums.SyncStatusDone),
					Ver:           int64(maxVer + 1),
				})
				if err != nil {
					return err
				}

				// 设置grpc商品属性键同步远程对象
				_, err = q.UpsertSyncRemote(ctx, sqlc.UpsertSyncRemoteParams{
					SyncID:    syncOfProductSpec.ID,
					RemoteObj: remoteObjOfProductSpec,
					RemotePk:  remotePkOfProductSpec,
					// Data:      []byte(item.SyncRemoteData),
				})

				if err != nil {
					return err
				}
			}
			slog.Infof("13 批量插入商品规格、grpc商品规格同步映射、grpc商品规格同步日志、grpc商品规格同步远程对象 ok")
		} else {
			slog.Infof("无规格商品")
		}
		// productSpecs, err = q.ListNormalProductSpecsByProductID(ctx, product.ID)
		// if err != nil {
		// 	return err
		// }
		// slog.Info("18 读取插入的产品规格 ok")
		return
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Product = transformProductEntityToPb(productAttributeKeys, productAttributeValues, productSpecs)(product)
	return
}

// UpdateProductOld 更新商品
func (s *ProductAPIService) UpdateProductOld(ctx context.Context, req *productGrpc.UpdateProductRequest) (res *productGrpc.UpdateProductResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("productImp->UpdateProductOld:%v", req)
	res = &productGrpc.UpdateProductResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	var product sqlc.Product
	var productAttributeKeys []sqlc.ProductAttributeKey
	var productAttributeValues []sqlc.ProductAttributeValue
	var productSpecs []sqlc.ProductSpec
	var priceMin int32
	var priceMax int32

	hasSpecs := len(req.ProductSpecs) > 0

	productID := req.Id
	// 更新前置分析
	noramlProductAttributeKeysExist, err := s.dao.Q.ListNormalProductAttributeKeysByProductID(ctx, productID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	var newKeyValues []string
	// 找出需要disabled的keys
	newKeyNames := util.MapToString(util.ToGenericSlice(req.ProductAttributeDefs), func(v interface{}) string {
		def := v.(*productGrpc.ProductAttributeDefEntity)
		newKeyValues = append(newKeyValues, def.Values...)
		return def.Key
	})
	toDisableKeyIDs := util.MapToInt64(util.Filter(util.ToGenericSlice(noramlProductAttributeKeysExist), func(v interface{}) bool {
		key := v.(sqlc.ProductAttributeKey)
		return !util.StringContains(newKeyNames, key.Name)
	}), func(v interface{}) int64 {
		key := v.(sqlc.ProductAttributeKey)
		return key.ID
	})
	slog.Infof("toDisableKeyIDs->%v", toDisableKeyIDs)

	normalProductAttributeValuesExist, err := s.dao.Q.ListNormalProductAttributeValuesByProductID(ctx, productID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	// 找出需要disabled的values
	toDisableValueIDs1 := util.MapToInt64(util.Filter(util.ToGenericSlice(normalProductAttributeValuesExist), func(v interface{}) bool {
		val := v.(sqlc.ProductAttributeValue)
		return !util.StringContains(newKeyValues, val.Value)
	}), func(v interface{}) int64 {
		val := v.(sqlc.ProductAttributeValue)
		return val.ID
	})
	slog.Infof("toDisableValueIDs1 from newValues->%v", toDisableValueIDs1)

	productAttributeValuesOfToDisableKeys, err := s.dao.Q.ListNormalProductAttributeValuesByProductAttributeKeyIDs(ctx, toDisableKeyIDs)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	toDisableValueIDs2 := util.MapToInt64(util.ToGenericSlice(productAttributeValuesOfToDisableKeys), func(v interface{}) int64 {
		val := v.(sqlc.ProductAttributeValue)
		return val.ID
	})
	slog.Infof("toDisableValueIDs2->%v", toDisableValueIDs2)

	toDisableValueIDs := append(toDisableValueIDs1, toDisableValueIDs2...)
	slog.Infof("toDisableValueIDs->%v", toDisableValueIDs)

	newSpecNames := util.MapToString(util.ToGenericSlice(req.ProductSpecs), func(v interface{}) string {
		specEntity := v.(*productGrpc.ProductSpecEntity)
		return specEntity.Name
	})

	productSpecsExist, err := s.dao.Q.ListNormalProductSpecsByProductID(ctx, productID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	toDisableSpecIDs := util.MapToInt64(util.Filter(util.ToGenericSlice(productSpecsExist), func(v interface{}) bool {
		spec := v.(sqlc.ProductSpec)
		return !util.StringContains(newSpecNames, spec.Name)
	}), func(v interface{}) int64 {
		val := v.(sqlc.ProductSpec)
		return val.ID
	})
	slog.Infof("toDisableSpecIDs->%v", toDisableSpecIDs)

	if hasSpecs {
		maxProductSpec, minProductSpec := util.MaxWithMin(util.ToGenericSlice(req.ProductSpecs), func(i1, i2 interface{}) util.Ord {
			ps1, ps2 := i1.(*productGrpc.ProductSpecEntity), i2.(*productGrpc.ProductSpecEntity)
			return (util.IfThenElse(ps1.Price-ps2.Price < 0, util.Lt, util.Gt)).(util.Ord)
		})
		priceMax, priceMin = maxProductSpec.(*productGrpc.ProductSpecEntity).Price, minProductSpec.(*productGrpc.ProductSpecEntity).Price
	} else {
		priceMax = req.Price
		priceMin = req.Price
	}
	slog.Infof("max,min %v, %v", priceMax, priceMin)

	slog.Info("更新前置分析完毕")

	err = s.dao.NewTxRunner().ExecTx(ctx, func(tx *sql.Tx) (err error) {

		q := sqlc.New(tx)

		txTime := time.Now()
		syncAction := string(sqlc.EmSyncActionLUR)

		product, err = q.UpdateProduct(ctx, sqlc.UpdateProductParams{
			ID:              req.Id,
			Name:            req.Name,
			Pics:            req.Pics,
			Intro:           sqlc.NSFromString(req.Intro),
			IntroPics:       req.IntroPics,
			HasSpecs:        hasSpecs,
			PriceMin:        priceMin,
			PriceMax:        priceMax,
			ProductGroupID:  sqlc.NInt64FromInt64(req.ProductGroupId),
			// RemotePrdTypeID: req.RemotePrdTypeId,
		})
		if err != nil {
			return err
		}
		slog.Info("1更新商品 ok")
		localPKOfProduct := strconv.FormatInt(product.ID, 10)
		remotePkOfProduct := strconv.FormatInt(product.RemotePk, 10)

		//2 商品设置同步
		localObjOfProduct, localPkNameOfProduct, localFieldsOfProduct := constants.SyncLocalObjProduct, constants.SyncLocalPkNameProduct, constants.SyncLocalFieldsProduct
		remoteObjOfProduct, remotePkNameOfProduct, remoteFieldsOfProduct := constants.SyncRemoteObjProduct, constants.SyncRemotePkNameProduct, constants.SyncRemoteFieldsProduct

		syncOfProduct, err := q.UpsertSync(ctx, sqlc.UpsertSyncParams{
			LocalObj:         localObjOfProduct,
			LocalPkName:      localPkNameOfProduct,
			LocalFields:      localFieldsOfProduct,
			RemoteObj:        remoteObjOfProduct,
			RemotePkName:     remotePkNameOfProduct,
			RemoteFields:     remoteFieldsOfProduct,
			LatestSynced:     txTime,
			LatestSyncAction: syncAction,
		})
		if err != nil {
			return err
		}
		slog.Info("2 grpc商品同步 ok")

		// 3 设置同步映射
		syncMappingOfProduct, err := q.UpsertSyncMapping(ctx, sqlc.UpsertSyncMappingParams{
			SyncID:    syncOfProduct.ID,
			LocalObj:  localObjOfProduct,
			LocalPk:   localPKOfProduct,
			RemoteObj: remoteObjOfProduct,
			RemotePk:  remotePkOfProduct,
		})
		if err != nil {
			return err
		}
		slog.Info("3 grpc商品同步映射 ok")

		// 4 设置同步日志
		syncDataOfProduct, err := json.Marshal(product)
		if err != nil {
			return err
		}

		maxVer, err := q.GetSyncLogMaxVer(ctx, sqlc.NInt64FromInt64(syncMappingOfProduct.ID))
		if err != nil {
			return err
		}
		_, err = q.CreateSyncLog(ctx, sqlc.CreateSyncLogParams{
			SyncID:        syncOfProduct.ID,
			SyncMappingID: sqlc.NInt64FromInt64(syncMappingOfProduct.ID),
			LocalObj:      localObjOfProduct,
			LocalPk:       localPKOfProduct,
			RemoteObj:     remoteObjOfProduct,
			RemotePk:      remotePkOfProduct,
			Synced:        txTime,
			Action:        syncAction,
			Data:          syncDataOfProduct,
			SyncStatus:    string(enums.SyncStatusDone),
			Ver:           int64(maxVer + 1),
		})
		if err != nil {
			return err
		}
		slog.Info("4 grpc商品同步日志 ok")

		// 5 设置同步远程对象
		_, err = q.UpsertSyncRemote(ctx, sqlc.UpsertSyncRemoteParams{
			SyncID:    syncOfProduct.ID,
			RemoteObj: remoteObjOfProduct,
			RemotePk:  remotePkOfProduct,
			// Data:      []byte(req.SyncRemoteData),
		})

		if err != nil {
			return err
		}
		slog.Info("5 grpc商品同步远程对象 ok")

		if len(toDisableKeyIDs) > 0 {
			disableKeysRet, err := q.DisableProductAttributeKeyByIDs(ctx, toDisableKeyIDs)
			if err != nil {
				return err
			}
			slog.Infof("6 disable商品属性键 ok %v", disableKeysRet)
		} else {
			slog.Info("6 没有要disable的商品属性键 ok")
		}

		if len(toDisableValueIDs) > 0 {
			disableValuesRet, err := q.DisableProductAttributeValueByIDs(ctx, toDisableValueIDs)
			if err != nil {
				return err
			}
			slog.Infof("7 disable商品属性值 ok %v", disableValuesRet)
		} else {
			slog.Info("7 没有要disable的商品属性值 ok")
		}

		if len(toDisableSpecIDs) > 0 {
			disableSpecsRet, err := q.DisableProductSpecByIDs(ctx, toDisableSpecIDs)
			if err != nil {
				return err
			}
			slog.Infof("8 disable商品规格 ok %v", disableSpecsRet)
		} else {
			slog.Info("8 没有要disable的商品规格 ok")
		}

		//12 商品属性键设置同步
		localObjOfProductAttributeKey, localPkNameOfProductAttributeKey, localFieldsOfProductAttributeKey := constants.SyncLocalObjProductAttributeKey, constants.SyncLocalPkNameProductAttributeKey, constants.SyncLocalFieldsProductAttributeKey
		remoteObjOfProductAttributeKey, remotePkNameOfProductAttributeKey, remoteFieldsOfProductAttributeKey := constants.SyncRemoteObjProductAttributeKey, constants.SyncRemotePkNameProductAttributeKey, constants.SyncRemoteFieldsProductAttributeKey

		syncOfProductAttributeKey, err := q.UpsertSync(ctx, sqlc.UpsertSyncParams{
			LocalObj:         localObjOfProductAttributeKey,
			LocalPkName:      localPkNameOfProductAttributeKey,
			LocalFields:      localFieldsOfProductAttributeKey,
			RemoteObj:        remoteObjOfProductAttributeKey,
			RemotePkName:     remotePkNameOfProductAttributeKey,
			RemoteFields:     remoteFieldsOfProductAttributeKey,
			LatestSynced:     txTime,
			LatestSyncAction: syncAction,
		})
		if err != nil {
			return err
		}
		slog.Info("9 grpc商品属性键同步 ok")

		var syncMappingOfProductAttributeKey sqlc.SyncMapping
		for idx1, item1 := range req.ProductAttributeDefs {
			r1, err := q.UpsertProductAttributeKey(ctx, sqlc.UpsertProductAttributeKeyParams{
				ProductID: product.ID,
				Name:      item1.Key,
				SortNo:    int32(idx1 + 1),
			})
			if err != nil {
				return err
			}
			productAttributeKeys = append(productAttributeKeys, r1)
			for idx2, item2 := range item1.Values {
				r2, err := q.UpsertProductAttributeValue(ctx, sqlc.UpsertProductAttributeValueParams{
					ProductID:             product.ID,
					ProductAttributeKeyID: r1.ID,
					Value:                 item2,
					SortNo:                int32(idx2 + 1),
				})
				if err != nil {
					return err
				}
				productAttributeValues = append(productAttributeValues, r2)
			}

			localPKOfProductAttributeKey := strconv.FormatInt(r1.ID, 10)
			remotePkOfProductAttributeKey := "-1" //strconv.FormatInt(r1.RemotePk, 10)
			// 设置grpc商品属性键同步映射
			syncMappingOfProductAttributeKey, err = q.UpsertSyncMapping(ctx, sqlc.UpsertSyncMappingParams{
				SyncID:    syncOfProductAttributeKey.ID,
				LocalObj:  localObjOfProductAttributeKey,
				LocalPk:   localPKOfProductAttributeKey,
				RemoteObj: remoteObjOfProductAttributeKey,
				RemotePk:  remotePkOfProductAttributeKey,
			})
			if err != nil {
				return err
			}

			// 设置grpc商品属性键同步日志
			syncDataOfProductAttributekey, err := json.Marshal(r1)
			if err != nil {
				return err
			}

			maxVer, err := q.GetSyncLogMaxVer(ctx, sqlc.NInt64FromInt64(syncMappingOfProductAttributeKey.ID))
			if err != nil {
				return err
			}
			_, err = q.CreateSyncLog(ctx, sqlc.CreateSyncLogParams{
				SyncID:        syncOfProductAttributeKey.ID,
				SyncMappingID: sqlc.NInt64FromInt64(syncMappingOfProductAttributeKey.ID),
				LocalObj:      localObjOfProductAttributeKey,
				LocalPk:       localPKOfProductAttributeKey,
				RemoteObj:     remoteObjOfProductAttributeKey,
				RemotePk:      remotePkOfProductAttributeKey,
				Synced:        txTime,
				Action:        syncAction,
				Data:          syncDataOfProductAttributekey,
				SyncStatus:    string(enums.SyncStatusDone),
				Ver:           int64(maxVer + 1),
			})
			if err != nil {
				return err
			}

			// 设置grpc商品属性键同步远程对象
			_, err = q.UpsertSyncRemote(ctx, sqlc.UpsertSyncRemoteParams{
				SyncID:    syncOfProductAttributeKey.ID,
				RemoteObj: remoteObjOfProductAttributeKey,
				RemotePk:  "0", //strconv.FormatInt(item1.RemotePk, 10),
				// Data:      []byte(item1.SyncRemoteData),
			})

			if err != nil {
				return err
			}
		}
		slog.Infof("10 批量upsert产品属性键/值、grpc商品属性键映射同步、grpc商品属性键日志同步、grpc商品属性键同步远程对象 ok")

		var produceSpec sqlc.ProductSpec
		var syncMappingOfProductSpec sqlc.SyncMapping
		//11 商品设置同步
		localObjOfProductSpec, localPkNameOfProductSpec, localFieldsOfProductSpec := constants.SyncLocalObjProductSpec, constants.SyncLocalPkNameProductSpec, constants.SyncLocalFieldsProductSpec
		remoteObjOfProductSpec, remotePkNameOfProductSpec, remoteFieldsOfProductSpec := constants.SyncRemoteObjProductSpec, constants.SyncRemotePkNameProductSpec, constants.SyncRemoteFieldsProductSpec
		syncOfProductSpec, err := q.UpsertSync(ctx, sqlc.UpsertSyncParams{
			LocalObj:         localObjOfProductSpec,
			LocalPkName:      localPkNameOfProductSpec,
			LocalFields:      localFieldsOfProductSpec,
			RemoteObj:        remoteObjOfProductSpec,
			RemotePkName:     remotePkNameOfProductSpec,
			RemoteFields:     remoteFieldsOfProductSpec,
			LatestSynced:     txTime,
			LatestSyncAction: syncAction,
		})
		if err != nil {
			return err
		}
		slog.Info("11 grpc商品规格同步 ok")
		for _, item := range req.ProductSpecs {
			produceSpec, err = q.UpsertProductSpec(ctx, sqlc.UpsertProductSpecParams{
				Origin:            product.Origin,
				BrandID:           product.BrandID,
				ProductID:         product.ID,
				ProductAttributes: json.RawMessage(item.ProductAttributes),
				Name:              item.Name,
				Price:             item.Price,
				RemotePk:          0, //item.RemotePk,
			})
			if err != nil {
				return err
			}

			productSpecs = append(productSpecs, produceSpec)

			localPKOfProductSpec := strconv.FormatInt(produceSpec.ID, 10)
			remotePkOfProductSpec := strconv.FormatInt(produceSpec.RemotePk, 10)
			// 设置商品规格同步映射
			syncMappingOfProductSpec, err = q.UpsertSyncMapping(ctx, sqlc.UpsertSyncMappingParams{
				SyncID:    syncOfProductSpec.ID,
				LocalObj:  localObjOfProductSpec,
				LocalPk:   localPKOfProductSpec,
				RemoteObj: remoteObjOfProductSpec,
				RemotePk:  remotePkOfProductSpec,
			})
			if err != nil {
				return err
			}

			// 10 设置商品规格同步日志
			syncDataOfProductSpec, err := json.Marshal(produceSpec)
			if err != nil {
				return err
			}
			maxVer, err := q.GetSyncLogMaxVer(ctx, sqlc.NInt64FromInt64(syncMappingOfProductSpec.ID))
			if err != nil {
				return err
			}
			_, err = q.CreateSyncLog(ctx, sqlc.CreateSyncLogParams{
				SyncID:        syncOfProductSpec.ID,
				SyncMappingID: sqlc.NInt64FromInt64(syncMappingOfProductSpec.ID),
				LocalObj:      localObjOfProductSpec,
				LocalPk:       localPKOfProductSpec,
				RemoteObj:     remoteObjOfProductSpec,
				RemotePk:      remotePkOfProductSpec,
				Synced:        txTime,
				Action:        syncAction,
				Data:          syncDataOfProductSpec,
				SyncStatus:    string(enums.SyncStatusDone),
				Ver:           int64(maxVer + 1),
			})
			if err != nil {
				return err
			}

			// 设置grpc商品属性键同步远程对象
			_, err = q.UpsertSyncRemote(ctx, sqlc.UpsertSyncRemoteParams{
				SyncID:    syncOfProductSpec.ID,
				RemoteObj: remoteObjOfProductSpec,
				RemotePk:  remotePkOfProductSpec,
				// Data:      []byte(item.SyncRemoteData),
			})
			if err != nil {
				return err
			}
		}
		slog.Infof("12 批量upsert商品规格、设置商品规格同步映射、设置商品规格同步日志、设置grpc商品属性键同步远程对象 ok")

		return
	})

	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Product = transformProductEntityToPb(productAttributeKeys, productAttributeValues, productSpecs)(product)
	return
}
